﻿using Blm.Utils.Extensions;
using Language.Resource;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using VisionCloud.Core.Model.Sys;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.DtoModel.Sys;
using VisionCloud.Domain.Extension;
using VisionCloud.Domain.Repository.Interface.Sys;
using VisionCloud.Domain.UnitOfWork;
using VisionCloud.Utility;
using VisionCloud.Utility.Extensions;

namespace VisionCloud.Service.Sys
{
    public class SysOrgService
    {
        private static string _fileServer = ConfigHelper.GetValue<string>("FileServer");

        public IUnitOfWork unitOfWork { get; set; }

        public ISysOrgRepository sysOrgRepository { get; set; }

        public ISysCodeFlowRepository sysCodeFlowRepository { get; set; }

        public ISysUserRepository sysUserRepository { get; set; }

        public ISysOrgUserRepository sysOrgUserRepository { get; set; }

        /// <summary>
        /// 多语言资源类
        /// </summary>
        public IStringLocalizer<ServiceResource> ServiceLocalizer { get; set; }

        public async Task<ApiResult> CreatAsync(SysOrgDto sysOrgDto)
        {
            var entity = sysOrgDto.CopyTo<SysOrg>();
            entity.Name = entity.Name.Trim();

            if (sysOrgDto.SuperId.IsNullOrWhiteSpace() || !Guid.TryParse(sysOrgDto.SuperId, out Guid result1))
            {
                var num = await sysOrgRepository.GetAll().CountAsync(t => t.Name == sysOrgDto.Name.Trim() && !t.IsDeleted);
                if (num >= 1)
                {
                    return new ApiResult(Domain.Common.AjaxCode.Fail, ServiceLocalizer["YB0328"].Value);
                }
            }
            if (Guid.TryParse(sysOrgDto.SuperId, out Guid result) && result != Guid.Empty)
            {
                var num = await sysOrgRepository.GetAll().CountAsync(t => t.SuperOrgId == result && t.Name == sysOrgDto.Name.Trim() && !t.IsDeleted);
                if (num >= 1)
                {
                    return new ApiResult(Domain.Common.AjaxCode.Fail, ServiceLocalizer["YB0328"].Value);
                }
                entity.SuperOrgId = sysOrgDto.SuperId.ToGuid();
                var superEntity = await sysOrgRepository.GetByIdAsync(sysOrgDto.SuperId.ToGuid());
                if (superEntity.IsNotNull())
                {
                    sysOrgDto.SuperCode = superEntity.Code;
                    superEntity.IsLast = false;
                }
            }
            var level = (sysOrgDto.SuperCode?.Trim()?.Length ?? 0) / 4;
            var sysCodeFlow = await sysCodeFlowRepository.FirstOrDefaultAsync(t => t.TableName == nameof(SysOrg) && t.Level == level);
            if (sysCodeFlow.IsNull())
            {
                entity.Code = $"{sysOrgDto.SuperCode?.Trim()}0001";
                sysCodeFlowRepository.Add(new SysCodeFlow { Level = level, MaxIndex = 1, TableName = nameof(SysOrg) });
            }
            else
            {
                sysCodeFlow.MaxIndex++;
                entity.Code = $"{sysOrgDto.SuperCode?.Trim()}{sysCodeFlow.MaxIndex.ToString().PadLeft(4, '0')}";
                sysCodeFlowRepository.Update(sysCodeFlow);
            }
            sysOrgRepository.Add(entity);
            await unitOfWork.SaveChangesAsync();
            return ApiResult.Success().SetData(entity.Id);
        }

        public async Task<ApiDataResult<List<SysOrgTreeView>>> GetOrgTree()
        {
            var data = await sysOrgRepository.GetAll().Where(t => !t.IsDeleted).ToListAsync();

            return new ApiDataResult<List<SysOrgTreeView>>(data.Where(t => !t.SuperOrgId.HasValue).Select(t => TransferModel(t)).ToList());
        }

        private SysOrgTreeView TransferModel(SysOrg sysOrg) => new SysOrgTreeView
        {
            id = sysOrg.Id.ToString(),
            name = sysOrg.Name,
            superId = sysOrg.SuperOrgId.ToString(),
            children = sysOrg.SubOrgs?.Select(t => TransferModel(t)).ToList()
        };

        public async Task<ApiPageResult> GetPage(SysOrgPageDto pageDto)
        {
            var query = sysOrgRepository.GetAll().Where(w => !w.SuperOrgId.HasValue).Include(i => i.SubOrgs).AsQueryable().AsNoTracking();
            if (!string.IsNullOrEmpty(pageDto.Query))
                query = query.Where(t => t.Name.Contains(pageDto.Query) || t.Description.Contains(pageDto.Query));
            var records = await query.OrderBy(o => o.CreatedDate).ToPageList(pageDto);
            var result = pageDto.CopyTo<ApiPageResult>();
            result.PageData = records;
            return result;
        }

        public async Task<ApiDataResult<List<SysOrgTreeDto>>> GetSubOrgs(String superId)
        {
            string comOrgCode = string.Empty;
            //系统管理员可以全部看到。该公司的用户只能看到自身所在公司的组织架构数据
            string orgCode = OperatorProvider.Get().OrgCode;
            string roleCode = OperatorProvider.Get().RoleCode;

            if (roleCode != "cloud_measure_robot_master")//不是测量机器人超级管理组
            {
                if (!string.IsNullOrEmpty(orgCode) && orgCode.Length >= 4)
                {
                    comOrgCode = orgCode.Substring(0, 4);//公司级别代码
                }
            }
            else
            {
                comOrgCode = "*";
            }

            var records = new List<SysOrg>();
            if (!Guid.TryParse(superId, out Guid result) && result == Guid.Empty)
            {
                records = await sysOrgRepository.GetAll().Where(w => (w.Code.Substring(0, 4) == comOrgCode || comOrgCode == "*") && !w.SuperOrgId.HasValue && !w.IsDeleted)
                     .Include(t => t.SysOrgUsers)
                         .ThenInclude(t => t.SysUser.SysUserRoles)
                             .ThenInclude(s => s.Role)
                      .Include(t => t.SysOrgUsers)
                         .ThenInclude(t => t.SysUser.SysFile).OrderBy(t => t.CreatedDate).ToListAsync();
            }
            else
            {
                records = await sysOrgRepository.GetAll().Where(w => (w.Code.Substring(0, 4) == comOrgCode || comOrgCode == "*") && w.SuperOrgId == superId.ToGuid() && !w.IsDeleted)
                     .Include(t => t.SysOrgUsers)
                         .ThenInclude(t => t.SysUser)
                             .ThenInclude(s => s.SysUserRoles)
                             .ThenInclude(s => s.Role)
                      .Include(t => t.SysOrgUsers)
                         .ThenInclude(t => t.SysUser.SysFile).OrderBy(t => t.CreatedDate).ToListAsync();
            }

            var data = new ApiDataResult<List<SysOrgTreeDto>>(records.Select(s => new SysOrgTreeDto
            {
                id = s.Id.ToString(),
                name = s.Name,
                description = s.Description,
                isLast = s.IsLast,
                members = s.SysOrgUsers
                  .GroupBy(c => c.SysUserId).Select(c => c.First())
                  .Select(t =>
                  {
                      if (t.SysUser?.SysFile.IsNotNull() ?? false)
                          t.SysUser.AvatarUrl = _fileServer + t.SysUser.SysFile.RelativePath;
                      if (t.SysUser?.SysUserRoles?.Select(v => v.Role)?.IsNotEmpty() ?? false)
                      {
                          t.SysUser.RoleNames = string.Join(',', t.SysUser.SysUserRoles.Select(v => v.Role.Name));
                      }
                      return t.SysUser;
                  }).ToList(),
            }).ToList());

            return data;
        }

        public async Task<ApiDataResult<List<SysUser>>> GetSubUsers(string Id)
        {
            var key = Id.ToGuid();
            var records = await sysUserRepository.GetAll().Where(x => x.SysOrgUsers.Any(y => y.SysOrgId == key)).ToListAsync();
            return new ApiDataResult<List<SysUser>>(records);
        }

        public async Task<ApiPageResult> GetSubUsersByPage(SysOrgPageDto pageDto)
        {
            var key = pageDto.Id.ToGuid();
            if (key == Guid.Empty)
                throw new ArgumentException(nameof(pageDto.Id));
            var records = await sysUserRepository.GetAll().Where(x => x.SysOrgUsers.Any(y => y.SysOrgId == key)).ToPageList(pageDto);
            var result = pageDto.CopyTo<ApiPageResult>();
            result.PageData = records;
            return result;
        }

        public async Task<bool> AddUsers(SysOrgOPDto sysOrgOPDto)
        {
            if (sysOrgOPDto.UserIds.IsEmpty())
                throw new ArgumentException(nameof(sysOrgOPDto.UserIds));

            var key = sysOrgOPDto.Id.ToGuid();
            if (key == Guid.Empty)
                throw new ArgumentException(nameof(sysOrgOPDto.Id));

            sysOrgOPDto.UserIds.ForEach(f =>
            {
                if (f.ToGuid() != Guid.Empty)
                {
                    if (sysOrgUserRepository.GetAll().Count(t => t.SysOrgId == key && t.SysUserId == f.ToGuid()) <= 0)
                    {
                        sysOrgUserRepository.Add(new SysOrgUser { SysOrgId = key, SysUserId = f.ToGuid() });
                    }
                }
            });

            return (await unitOfWork.SaveChangesAsync()) > 0;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="sysOrgOPDto"></param>
        /// <returns></returns>
        public async Task<Boolean> RemoveUser(SysOrgOPDto sysOrgOPDto)
        {
            var key = sysOrgOPDto.Id.ToGuid();
            if (key == Guid.Empty)
                throw new ArgumentException(nameof(sysOrgOPDto.Id));

            sysOrgOPDto.UserIds.ForEach(f =>
            {
                if (f.ToGuid() != Guid.Empty)
                {
                    var entities = sysOrgUserRepository.GetAll().Where(t => t.SysUserId == f.ToGuid() && t.SysOrgId == key).ToList();
                    foreach (var entity in entities)
                    {
                        sysOrgUserRepository.Remove(entity, true);
                    }
                }
            });

            return (await unitOfWork.SaveChangesAsync()) > 0;
        }

        public async Task<ApiResult> DelOrg(SysOrgDto sysOrgDto)
        {
            var key = sysOrgDto.Id.ToGuid();
            var entity = await sysOrgRepository.GetAll().Include(t => t.SubOrgs).Include(t => t.SysOrgUsers).FirstOrDefaultAsync(t => t.Id == key);
            if (entity?.SubOrgs.IsEmpty() ?? false)
            {
                if (entity.SubOrgs.Count(t => !t.IsDeleted) > 0)
                {
                    return new ApiResult(Domain.Common.AjaxCode.Fail, ServiceLocalizer["YB0329"].Value);
                }
                if (entity.SysOrgUsers.Count() > 0)
                {
                    return new ApiResult(Domain.Common.AjaxCode.Fail, ServiceLocalizer["YB0330"].Value);
                }

                sysOrgRepository.Remove(entity, true);
            }

            await unitOfWork.SaveChangesAsync();
            var superId = entity?.SuperOrgId;
            if (superId.HasValue && superId != Guid.Empty)
            {
                var superEnity = await sysOrgRepository.GetAll().Include(t => t.SubOrgs)
                    .FirstOrDefaultAsync(t => t.Id == superId);
                if (superEnity?.SubOrgs?.Count(t => !t.IsDeleted) <= 0)
                {
                    superEnity.IsLast = true;
                }
            }
            await unitOfWork.SaveChangesAsync();

            return ApiResult.Success();
        }
    }
}